#pragma once

#include "Reflection/Reflection.h"
#include "ByteCodeInstruction.m.h"


RENUM()
enum class EByteCodeInstructions
{
    Add_i8,    // add 1byte int 
    Add_i16,   // add 2byte int
    Add_i32,   // add 4byte int
    Add_i64,   // add 8byte int
    Add_u8,    // add 1byte unsigned int
    Add_u16,   // add 2byte unsigned int
    Add_u32,   // add 4byte unsigned int
    Add_u64,   // add 8byte unsigned int
    Add_f32,   // add 4byte float
    Add_f64,   // add 8byte float

    Add_String, // add two string

    And,       // '&&' between two bool value

    Box,       // box a value type to a reference type

    Br,        // branch to a instruction

    BrEqual,   // if value1 == value2 , branch to a instruction
    
    BrFalse,   // if value ==0 , branch to a instruction

    BrTrue,    // if value !=0  , branch to a instruction

    Call,      // call a function

    CallVirt,  // call a virtual function

    CastClass,      // cast a value to another type

    Compare_Equal_i8,       // compare equal
    Compare_Equal_i16,
    Compare_Equal_i32,
    Compare_Equal_i64,
    Compare_Equal_u8,      
    Compare_Equal_u16,
    Compare_Equal_u32,
    Compare_Equal_u64,
    Compare_Equal_f32,
    Compare_Equal_f64, 
    Compare_Equal_Bool,
    Compare_Equal_Char,
    Compare_Equal_String,
    Compare_Equal_Object,

    
    Compare_NotEqual_i8,    // compare not equal
    Compare_NotEqual_i16,
    Compare_NotEqual_i32,
    Compare_NotEqual_i64,
    Compare_NotEqual_u8,
    Compare_NotEqual_u16,
    Compare_NotEqual_u32,
    Compare_NotEqual_u64,
    Compare_NotEqual_f32,
    Compare_NotEqual_f64,
    Compare_NotEqual_Bool,
    Compare_NotEqual_Char,
    Compare_NotEqual_String,
    Compare_NotEqual_Object,

    Compare_Greater_i8,       // compare greater than
    Compare_Greater_i16,
    Compare_Greater_i32,
    Compare_Greater_i64,
    Compare_Greater_u8,
    Compare_Greater_u16,
    Compare_Greater_u32,
    Compare_Greater_u64,
    Compare_Greater_f32,
    Compare_Greater_f64,

    Compare_GreaterEqual_i8,       // compare greater than or equal
    Compare_GreaterEqual_i16,
    Compare_GreaterEqual_i32,
    Compare_GreaterEqual_i64,
    Compare_GreaterEqual_u8,
    Compare_GreaterEqual_u16,
    Compare_GreaterEqual_u32,
    Compare_GreaterEqual_u64,
    Compare_GreaterEqual_f32,
    Compare_GreaterEqual_f64,

    Compare_Less_i8,       // compare less than
    Compare_Less_i16,
    Compare_Less_i32,
    Compare_Less_i64,
    Compare_Less_u8,
    Compare_Less_u16,
    Compare_Less_u32,
    Compare_Less_u64,
    Compare_Less_f32,
    Compare_Less_f64,

    Compare_LessEqual_i8,       // compare less than or equal
    Compare_LessEqual_i16,
    Compare_LessEqual_i32,
    Compare_LessEqual_i64,
    Compare_LessEqual_u8,
    Compare_LessEqual_u16,
    Compare_LessEqual_u32,
    Compare_LessEqual_u64,
    Compare_LessEqual_f32,
    Compare_LessEqual_f64,

    Convert_i8_To_i16,    // convert a 1byte int to a 2byte int 
    Convert_i8_To_i32,
    Convert_i8_To_i64,
    Convert_i8_To_u8,
    Convert_i8_To_u16,
    Convert_i8_To_u32,
    Convert_i8_To_u64,
    Convert_i8_To_r32,
    Convert_i8_To_r64,
    Convert_i8_To_Bool,
    Convert_i8_To_Char,

    Convert_i16_To_i8,
    Convert_i16_To_i32,
    Convert_i16_To_i64,
    Convert_i16_To_u8,
    Convert_i16_To_u16,
    Convert_i16_To_u32,
    Convert_i16_To_u64,
    Convert_i16_To_r32,
    Convert_i16_To_r64,
    Convert_i16_To_Bool,
    Convert_i16_To_Char,

    Convert_i32_To_i8,
    Convert_i32_To_i16,
    Convert_i32_To_i64,
    Convert_i32_To_u8,
    Convert_i32_To_u16,
    Convert_i32_To_u32,
    Convert_i32_To_u64,
    Convert_i32_To_r32,
    Convert_i32_To_r64,
    Convert_i32_To_Bool,
    Convert_i32_To_Char,

    Convert_i64_To_i8,
    Convert_i64_To_i16,
    Convert_i64_To_i32,
    Convert_i64_To_u8,
    Convert_i64_To_u16,
    Convert_i64_To_u32,
    Convert_i64_To_u64,
    Convert_i64_To_r32,
    Convert_i64_To_r64,
    Convert_i64_To_Bool,
    Convert_i64_To_Char,

    Convert_u8_To_i8,
    Convert_u8_To_i16,
    Convert_u8_To_i32,
    Convert_u8_To_i64,
    Convert_u8_To_u16,
    Convert_u8_To_u32,
    Convert_u8_To_u64,
    Convert_u8_To_r32,
    Convert_u8_To_r64,
    Convert_u8_To_Bool,
    Convert_u8_To_Char,

    Convert_u16_To_i8,
    Convert_u16_To_i16,
    Convert_u16_To_i32,
    Convert_u16_To_i64,
    Convert_u16_To_u8,
    Convert_u16_To_u32,
    Convert_u16_To_u64,
    Convert_u16_To_r32,
    Convert_u16_To_r64,
    Convert_u16_To_Bool,
    Convert_u16_To_Char,

    Convert_u32_To_i8,
    Convert_u32_To_i16,
    Convert_u32_To_i32,
    Convert_u32_To_i64,
    Convert_u32_To_u8,
    Convert_u32_To_u16,
    Convert_u32_To_u64,
    Convert_u32_To_r32,
    Convert_u32_To_r64,
    Convert_u32_To_Bool,
    Convert_u32_To_Char,

    Convert_u64_To_i8,
    Convert_u64_To_i16,
    Convert_u64_To_i32,
    Convert_u64_To_i64,
    Convert_u64_To_u8,
    Convert_u64_To_u16,
    Convert_u64_To_u32,
    Convert_u64_To_r32,
    Convert_u64_To_r64,
    Convert_u64_To_Bool,
    Convert_u64_To_Char,

    Convert_r32_To_i8,
    Convert_r32_To_i16,
    Convert_r32_To_i32,
    Convert_r32_To_i64,
    Convert_r32_To_u8,
    Convert_r32_To_u16,
    Convert_r32_To_u32,
    Convert_r32_To_u64,
    Convert_r32_To_r64,
    Convert_r32_To_Bool,
    Convert_r32_To_Char,

    Convert_r64_To_i8,
    Convert_r64_To_i16,
    Convert_r64_To_i32,
    Convert_r64_To_i64,
    Convert_r64_To_u8,
    Convert_r64_To_u16,
    Convert_r64_To_u32,
    Convert_r64_To_u64,
    Convert_r64_To_r32,
    Convert_r64_To_Bool,
    Convert_r64_To_Char,

    Convert_Bool_To_i8,
    Convert_Bool_To_i16,
    Convert_Bool_To_i32,
    Convert_Bool_To_i64,
    Convert_Bool_To_u8,
    Convert_Bool_To_u16,
    Convert_Bool_To_u32,
    Convert_Bool_To_u64,
    Convert_Bool_To_r32,
    Convert_Bool_To_r64,
    Convert_Bool_To_Char,

    Convert_Char_To_i8,
    Convert_Char_To_i16,
    Convert_Char_To_i32,
    Convert_Char_To_i64,
    Convert_Char_To_u8,
    Convert_Char_To_u16,
    Convert_Char_To_u32,
    Convert_Char_To_u64,
    Convert_Char_To_r32,
    Convert_Char_To_r64,
    Convert_Char_To_Bool,

    Divide_i8,    // divide 1byte int
    Divide_i16,   // divide 2byte int
    Divide_i32,   // divide 4byte int
    Divide_i64,   // divide 8byte int
    Divide_u8,    // divide 1byte unsigned int
    Divide_u16,   // divide 2byte unsigned int
    Divide_u32,   // divide 4byte unsigned int
    Divide_u64,   // divide 8byte unsigned int
    Divide_f32,   // divide 4byte float
    Divide_f64,   // divide 8byte float

    Duplicate,  // duplicate the value on the top of the stack
    
    Ldarg,     // load a value from a argument variable onto the stack

    Ldarga,    // load a address of a argument variable onto the stack
    
    Ldc_Char,   // put a char32_t on the stack

    Ldc_i8,    // put a 1byte int on the stack

    Ldc_i16,  // put a 1byte int 0 on the stack

    Ldc_i32,    // put a 4byte int on the stack

    Ldc_i64,    // put a 8byte int on the stack
    
    Ldc_i64_0,  // put a 8byte int 0 on the stack

    Ldc_i64_1,  // put a 8byte int 1 on the stack

    Ldc_i64_2,  // put a 8byte int 2 on the stack

    Ldc_i64_3,  // put a 8byte int 3 on the stack

    Ldc_i64_4,  // put a 8byte int 4 on the stack

    Ldc_i64_5,  // put a 8byte int 5 on the stack

    Ldc_i64_6,  // put a 8byte int 6 on the stack

    Ldc_i64_7,  // put a 8byte int 7 on the stack

    Ldc_i64_8,  // put a 8byte int 8 on the stack

    Ldc_i64_m1, // put a 8byte int -1 on the stack

    Ldc_i64_s,  // put a 1byte int on the stack ,and extend to 8byte

    Ldc_u8,    // put a 1byte unsigned int on the stack

    Ldc_u16,   // put a 2byte unsigned int on the stack

    Ldc_u32,   // put a 4byte unsigned int on the stack

    Ldc_u64,   // put a 8byte unsigned int on the stack

    Ldc_r32,    // put a 4byte float on the stack, r means real

    Ldc_r64,    // put a 8byte float on the stack

    Ldc_True,  // put a true bool on the stack

    Ldc_False,  // put a false bool on the stack
    
    Ldfld,     // load a value from a field onto the stack

    Ldflda,    // load a address of a field onto the stack
    
    Ldsfld,    // load a value from a static field onto the stack

    Ldsflda,   // load a address of a static field onto the stack

    Ldloc,     // load a value from a local variable onto the stack

    Ldloca,    // load a address of a local variable onto the stack

    Ldstr,     // load a string onto the stack

    LoadNullPtr,  // load a null pointer onto the stack

    LoadNullObject,  // load a null shared_ptr onto the stack

    LoadFunction, // load a function ptr onto the stack 

    Mod_i8,    // mod 1byte int
    Mod_i16,   // mod 2byte int
    Mod_i32,   // mod 4byte int
    Mod_i64,   // mod 8byte int
    Mod_u8,    // mod 1byte unsigned int
    Mod_u16,   // mod 2byte unsigned int
    Mod_u32,   // mod 4byte unsigned int
    Mod_u64,   // mod 8byte unsigned int

    Multiply_i8,    // multiple 1byte int
    Multiply_i16,   // multiple 2byte int
    Multiply_i32,   // multiple 4byte int
    Multiply_i64,   // multiple 8byte int
    Multiply_u8,    // multiple 1byte unsigned int
    Multiply_u16,   // multiple 2byte unsigned int
    Multiply_u32,   // multiple 4byte unsigned int
    Multiply_u64,   // multiple 8byte unsigned int
    Multiply_f32,   // multiple 4byte float
    Multiply_f64,   // multiple 8byte float

    New_Object, // create a new object
    Init_ValueType, // reset a valuetype to zero

    Negative_i8,    // Negative 1byte int
    Negative_i16,   // Negative 2byte int
    Negative_i32,   // Negative 4byte int
    Negative_i64,   // Negative 8byte int
    Negative_u8,    // Negative 1byte unsigned int
    Negative_u16,   // Negative 2byte unsigned int
    Negative_u32,   // Negative 4byte unsigned int
    Negative_u64,   // Negative 8byte unsigned int
    Negative_f32,   // Negative 4byte float
    Negative_f64,   // Negative 8byte float

    Nop,       // do nothing

    Or,        // Or between two bool value

    Pop,       // pop a value from the stack

    Ret,       // return from a function

    Starg,     // store a value from the stack into a argument variable

    Stloc,     // store a value from the stack into a local variable 

    Stfld,     // store a value from the stack into a field

    Stsfld,    // store a value from the stack into a static field

    Sub_i8,    // sub 1byte int
    Sub_i16,   // sub 2byte int
    Sub_i32,   // sub 4byte int
    Sub_i64,   // sub 8byte int
    Sub_u8,    // sub 1byte unsigned int
    Sub_u16,   // sub 2byte unsigned int
    Sub_u32,   // sub 4byte unsigned int
    Sub_u64,   // sub 8byte unsigned int
    Sub_f32,   // sub 4byte float
    Sub_f64,   // sub 8byte float


    Unbox_Any, // unbox a value type from a object reference
};